# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: xguo

import json
import logging
import numpy
import os
import time

from coin.experimental.xguo.fruit.base.single_product import SingleProductPriceCalculator
from coin.experimental.xguo.fruit.util.fee import get_fee_rate
from coin.experimental.xguo.fruit.util.util import FillStats
from datatool import OhlcCalculator, MovingWindowData


class PearPricerConfig(object):
  def __init__(self):
    # numbers
    self.window_period = int(300 * 1e9)
    self.book_level = 5
    self.price_pull = 20 * 1e-4
    self.price_push = 20 * 1e-4

    self.max_pos = None
    self.min_pos = None
    self.price_range = None

    # product
    self.trade_symbol = None
    self.ref_symbol = None
    self.get_pos = None

  def __str__(self):
    return json.dumps(self.__dict__, indent=2, default=str)


class PearPricer(object):
  def __init__(self, config):
    self._logger = logging.getLogger("PearPricer")
    self._timestamp = None
    self._config = config

    fee_bp = get_fee_rate(config.trade_symbol)[0]
    self._fee_rate = fee_bp * 1e-4
    self._fill_stats = FillStats(config.trade_symbol, fee_bp=fee_bp)
    self._last_valid_feed_ts = None

    price_calculator = SingleProductPriceCalculator(self._config.trade_symbol)
    self._tpc = price_calculator
    self._logger.info("PearPricer created for %s-%s", config.trade_symbol, config.ref_symbol)
    self._logger.info("config: %s", str(self._config))

  @property
  def trade_symbol(self):
    return self._config.trade_symbol

  @property
  def fill_stats(self):
    return self._fill_stats

  def get_pos(self):
    return self._config.get_pos(self.trade_symbol.base)

  def get_zero_centered_pos(self):
    reserve_pos = (self._config.max_pos + self._config.min_pos) / 2.
    return self.get_pos() - reserve_pos

  def get_norm_position(self):  # normalized to [-1, 1]
    pos_range = self._config.max_pos - self._config.min_pos

    if abs(pos_range) < 1e-5:
      return 0.0

    n_pos = 2 * (self.get_pos() - self._config.min_pos) / pos_range - 1
    return numpy.clip(n_pos, -1, 1)

  def is_ready(self):
    return len(self._ohlc.data) > 1 and self._fill_stats.is_initialized()

  def update_tick(self):
    self._tpc.renew_tick()
    if self._rpc is not None:
      self._rpc.renew_tick()

  def update(self, product, book):
    self._timestamp = book.timestamp
    self._tpc.update(book)
    if self._fill_stats.product == product:
      if not self._fill_stats.is_initialized():
        self._fill_stats.set_init_pos(self.get_zero_centered_pos())
      self._fill_stats.update_book(book)

  def update_fill(self, fill_price, fill_qty, order):
    self._fill_stats.update(fill_price, fill_qty, order)

  def gen_order(self):
    if not self._tpc.is_ready():
      return

    all_orders = {'product': str(self.trade_symbol)}
    if self._fill_stats.last_fill:
      sell_price = self._fill_stats.last_fill.fill_price * (1 + 60e-4)
      buy_price = self._fill_stats.last_fill.fill_price * (1 - 60e-4)
    else:
      sell_price = self._tpc.aks0 * (1 + 6e-4)
      buy_price = self._tpc.bid0 * (1 - 6e-4)

    pass_buy_price = self._tpc.get_prev_price(buy_price)
    pass_sell_price = self._tpc.get_next_price(sell_price)
    all_orders['mm'] = dict(
        pass_sell_price=pass_sell_price,
        pass_buy_price=pass_buy_price,
        sell_price_pull=None,
        buy_price_pull=None,
        sell_price_push=None,
        buy_price_push=None)
    all_orders['type'] = 'order'
    all_orders['pricer'] = 'pear_pricer'
    return all_orders
